from django.db import models
from django.contrib.auth.models import User
from django.core.validators import MinValueValidator, MaxValueValidator
import json


class Exam(models.Model):
    STATUS_CHOICES = (
        ('draft', 'Draft'),
        ('published', 'Published'),
        ('completed', 'Completed'),
    )
    
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    creator = models.ForeignKey(User, on_delete=models.CASCADE, related_name='created_exams')
    start_time = models.DateTimeField()
    end_time = models.DateTimeField()
    duration = models.PositiveIntegerField(help_text="Duration in minutes")
    total_score = models.PositiveIntegerField()
    passing_score = models.PositiveIntegerField()
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def is_available(self):
        """检查考试是否在可进行的时间范围内"""
        from django.utils import timezone
        now = timezone.now()
        return self.start_time <= now <= self.end_time

    def time_remaining(self, user):
        """返回用户剩余考试时间(秒)"""
        from django.utils import timezone
        attempt = self.attempts.filter(user=user).first()
        if not attempt or attempt.status != 'in_progress':
            return 0

        now = timezone.now()
        elapsed = (now - attempt.start_time).total_seconds()
        remaining = self.duration * 60 - elapsed
        return max(0, remaining)

    class Meta:
        verbose_name = "Exam"
        verbose_name_plural = "Exams"
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.title} (Status: {self.get_status_display()})"

class Question(models.Model):
    QUESTION_TYPES = (
        ('true_false', 'True/False'),
        ('single_choice', 'Single Choice'),
        ('multiple_choice', 'Multiple Choice'),
        ('programming', 'Programming'),
    )
    
    DIFFICULTY_LEVELS = (
        (1, 'Very Easy'),
        (2, 'Easy'),
        (3, 'Medium'),
        (4, 'Hard'),
        (5, 'Very Hard'),
    )
    
    exam = models.ForeignKey(Exam, on_delete=models.CASCADE, related_name='questions')
    type = models.CharField(max_length=20, choices=QUESTION_TYPES)
    content = models.TextField()
    score = models.PositiveIntegerField()
    difficulty = models.PositiveSmallIntegerField(choices=DIFFICULTY_LEVELS, default=3)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def get_question_type(self):
        """获取具体的问题类型实例"""
        if self.type == 'true_false':
            return self.true_false_question
        elif self.type == 'single_choice':
            return self.single_choice_question
        elif self.type == 'multiple_choice':
            return self.multiple_choice_question
        elif self.type == 'programming':
            return self.programming_question
        return None

    class Meta:
        verbose_name = "Question"
        verbose_name_plural = "Questions"
        ordering = ['created_at']
    
    def __str__(self):
        return f"{self.get_type_display()}: {self.content[:50]}..."

class TrueFalseQuestion(models.Model):
    question = models.OneToOneField(
        Question, 
        on_delete=models.CASCADE, 
        related_name='true_false_question',
        primary_key=True
    )
    correct_answer = models.BooleanField()
    
    class Meta:
        verbose_name = "True/False Question"
        verbose_name_plural = "True/False Questions"
    
    def __str__(self):
        return f"True/False: {self.question.content[:50]}..."

class SingleChoiceQuestion(models.Model):
    question = models.OneToOneField(
        Question, 
        on_delete=models.CASCADE, 
        related_name='single_choice_question',
        primary_key=True
    )
    options = models.JSONField(help_text="List of options as JSON array")
    correct_option = models.PositiveSmallIntegerField()
    
    class Meta:
        verbose_name = "Single Choice Question"
        verbose_name_plural = "Single Choice Questions"
    
    def get_options(self):
        return self.options if self.options else []
    
    def __str__(self):
        return f"Single Choice: {self.question.content[:50]}..."

class MultipleChoiceQuestion(models.Model):
    question = models.OneToOneField(
        Question, 
        on_delete=models.CASCADE, 
        related_name='multiple_choice_question',
        primary_key=True
    )
    options = models.JSONField(help_text="List of options as JSON array")
    correct_options = models.JSONField(help_text="List of correct option indices as JSON array")
    
    class Meta:
        verbose_name = "Multiple Choice Question"
        verbose_name_plural = "Multiple Choice Questions"
    
    def get_options(self):
        return self.options if self.options else []
    
    def get_correct_options(self):
        return self.correct_options if self.correct_options else []
    
    def __str__(self):
        return f"Multiple Choice: {self.question.content[:50]}..."

class ProgrammingQuestion(models.Model):
    LANGUAGE_CHOICES = (
        ('python', 'Python'),
        ('java', 'Java'),
        ('javascript', 'JavaScript'),
        ('c', 'C'),
        ('cpp', 'C++'),
    )
    
    question = models.OneToOneField(
        Question, 
        on_delete=models.CASCADE, 
        related_name='programming_question',
        primary_key=True
    )
    language = models.CharField(max_length=20, choices=LANGUAGE_CHOICES)
    template_code = models.TextField(blank=True)
    test_cases = models.JSONField(help_text="Test cases as JSON array")
    time_limit = models.PositiveIntegerField(help_text="Time limit in milliseconds", default=2000)
    memory_limit = models.PositiveIntegerField(help_text="Memory limit in MB", default=256)
    
    class Meta:
        verbose_name = "Programming Question"
        verbose_name_plural = "Programming Questions"
    
    def get_test_cases(self):
        return json.loads(self.test_cases)
    
    def __str__(self):
        return f"Programming ({self.get_language_display()}): {self.question.content[:50]}..."

class ExamAttempt(models.Model):
    STATUS_CHOICES = (
        ('in_progress', 'In Progress'),
        ('submitted', 'Submitted'),
        ('timeout', 'Timeout'),
    )
    
    exam = models.ForeignKey(Exam, on_delete=models.CASCADE, related_name='attempts')
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='exam_attempts')
    start_time = models.DateTimeField(auto_now_add=True)
    submit_time = models.DateTimeField(null=True, blank=True)
    status = models.CharField(max_length=12, choices=STATUS_CHOICES, default='in_progress')
    total_score = models.FloatField(null=True, blank=True)
    ip_address = models.GenericIPAddressField(null=True, blank=True)

    def calculate_score(self):
        """计算考试总得分"""
        total = 0
        for response in self.responses.all():
            if response.score is not None:
                total += response.score
        self.total_score = total
        self.save()
        return total

    class Meta:
        verbose_name = "Exam Attempt"
        verbose_name_plural = "Exam Attempts"
        unique_together = ('exam', 'user')
    
    def __str__(self):
        return f"{self.user.username}'s attempt for {self.exam.title}"

class QuestionResponse(models.Model):
    attempt = models.ForeignKey(ExamAttempt, on_delete=models.CASCADE, related_name='responses')
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    response = models.JSONField(help_text="Student's response in JSON format")
    score = models.FloatField(null=True, blank=True)
    feedback = models.TextField(blank=True)
    graded_by = models.ForeignKey(
        User, 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True, 
        related_name='graded_responses'
    )
    graded_at = models.DateTimeField(null=True, blank=True)
    
    class Meta:
        verbose_name = "Question Response"
        verbose_name_plural = "Question Responses"
        unique_together = ('attempt', 'question')
    
    def __str__(self):
        return f"Response for {self.question} by {self.attempt.user.username}"

class ProgrammingExecution(models.Model):
    response = models.OneToOneField(
        QuestionResponse, 
        on_delete=models.CASCADE, 
        related_name='execution_result',
        primary_key=True
    )
    test_case_results = models.JSONField(help_text="Test case results as JSON")
    execution_time = models.PositiveIntegerField(help_text="Execution time in milliseconds", null=True, blank=True)
    memory_usage = models.PositiveIntegerField(help_text="Memory usage in KB", null=True, blank=True)
    compilation_output = models.TextField(blank=True)
    execution_output = models.TextField(blank=True)
    
    class Meta:
        verbose_name = "Programming Execution"
        verbose_name_plural = "Programming Executions"
    
    def get_test_case_results(self):
        return json.loads(self.test_case_results)
    
    def __str__(self):
        return f"Execution result for {self.response}"
